/*
    Shader PositionTexturedAmbientDiffuseSpecular
*/    

//Matrices
float4x4 WorldViewProj : WorldViewProjection;
float4x4 World : World;
float4x4 ViewInverse : ViewInverse;

//Lumières
/*
    La LightPosition est utilisée à la fois pour 
    la lumière diffuse et la lumière spéculaire.
    Le bump est également généré depuis cette position
*/

float4 LightPosition[5] : Position
<
    string UIName = "Light Position";
    string Object = "PointLight";
> = {   {0, 20 , 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
};

float4 AmbientColor : Ambient 
<
    string UIName = "Ambient Color";
    string UIWidget = "Color";
> = {0.1, 0.1, 0.1, 0.4};

float4 DiffuseColor[5] : Diffuse
<
    string UIName = "Diffuse Color";
    string Object = "PointLight";
> = {   {0.8, 0.8, 0.8, 0.5},
        {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
};

float4 SpecularColor[5] : Specular
<
    string UIName = "Specular Color";
    string Object = "PointLight";
> = {   {1, 1, 1, 1},
        {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0},
        {0, 0, 0, 0}
};

float SpecExpon[5]
<
	string UIWidget = "slider";
	float UIMin = 1.0;
	float UIMax = 1024;
	float UIStep = 1.0;
	string UIName =  "Specular Power";
> = {512.0f, 512.0f, 512.0f, 512.0f, 512.0f};    

//Zones d'activité des lumières
float LightFallOffLimit1[5]
<   
    string UIWidget = "slider";
    float UIMin = 0.1;
    float UIMax = 100.0;
    float UIStep = 1.0;
    string UIName = "Light FallOff 1";
> = {50.0, 10.0, 10.0, 10.0, 10.0};

float LightFallOffLimit2[5]
<
    string UIWidget = "slider";
    float UIMin = 0.1;
    float UIMax = 100.0;
    float UIStep = 1.0;
    string UIName = "Light FallOff 2";
> = {100.0, 20.0, 20.0, 20.0, 20.0}; 


//Bump
float BumpIntensity
<
    string UIWidget = "slider";
    float UIMin = 0;
    float UIMax = 5;
    float UIStep = 0.2;
    string UIName = "Bump Intensity";
> = 1;  

//Parallax
float parallaxValue
<
    string UIWidget = "slider";
    float UIMin = 0.0;
    float UIMax = 0.4;
    float UIStep = 0.001;
    string UIName = "Parallax Value";
> = 0.05;  


//Textures
#ifndef TEXTURED_SURFACE

Texture coloredTexture : Diffuse
<
    string ResourceType = "2D";
    string UIName = "Texture";
>;
sampler coloredTextureSampler = sampler_state{
            texture = <coloredTexture>;
            magfilter = LINEAR;
            minfilter = LINEAR;
            mipfilter = LINEAR;
            };    
            
Texture normalTexture : Normal
<
    string ResourceType = "2D";
    string UIName = "Texture normales";
>;
sampler normalTextureSampler = sampler_state{
            texture = <normalTexture>;
            magfilter = LINEAR;
            minfilter = LINEAR;
            mipfilter = LINEAR;
};

Texture heightTexture : Normal
<
    string ResourceType = "2D";
    string UIName = "Texture hauteur";
>;
sampler heightTextureSampler = sampler_state{
            texture = <heightTexture>;
            magfilter = LINEAR;
            minfilter = LINEAR;
            mipfilter = LINEAR;
};
            
#endif

//Fonctions diverses
float norme(float3 vecteur){
    return sqrt( pow(vecteur.x, 2) + pow(vecteur.y, 2) + pow(vecteur.z, 2));
}

//Structures de données
//Entrée dans le shader
struct AppData{
    float4 position : POSITION;
    float2 texCoordinates : TEXCOORD0;  
    
    float3 normal : NORMAL0;
    float3 tangent : TANGENT;
    float3 binormal : BINORMAL;
};

//Sortie du vertexShader
struct VertexOutput{
    float4 position : POSITION;
    float2 texCoordinates : TEXCOORD0;
    
    float3 wP : TEXCOORD1;          //Position World       
    float3 wN : TEXCOORD2;          //Normales world    
    float3 wB : TEXCOORD3;          //Bitangentes world
    float3 wT : TEXCOORD4;          //Tangentes world
    float3 wV : TEXCOORD5;          //View world
    
    float3 tV : TEXCOORD6;          //View tangent
};


//Vertex shader
VertexOutput mainVS(AppData input){

    //Données de retour
    VertexOutput output = (VertexOutput)0;
    
    output.position = mul(input.position, (float4x4) WorldViewProj);
    output.texCoordinates = input.texCoordinates;
    
    output.wP = mul(input.position, World);             
    output.wN = mul(input.normal, (float3x3)World);
    output.wT = mul(input.binormal, (float3x3)World);
    output.wB = mul(input.tangent, (float3x3)World);
    output.wV = ViewInverse[3].xyz - output.wP;
    
    //Calcul du vecteur caméra dans le repère tangent (pour le parallax)
    float3x3 WorldToTangent = float3x3(output.wT, output.wB, output.wN);
    output.tV = mul(WorldToTangent, output.wV);
    
    return output;
}

float4 mainPS(VertexOutput input, uniform int numLight) : COLOR0 {
    float4 output = 0;
    const float sfHeightBias = parallaxValue * -0.5;
    
    //Calcul des variables utiles
    float3 wP = input.wP;                   //Position monde du vertex 
    float3 wN = normalize(input.wN);        //Normale monde
    float3 wV = normalize(input.wV);        //Vecteur caméra
    float3 wB = normalize(input.wB);        //Binormale world
    float3 wT = normalize(input.wT);        //Tangente world
    float3 wLd = LightPosition[numLight].xyz - wP;  //Vecteur vertex-lumière non normalisé
    float3 wL = normalize(wLd);                     //Vecteur vertex-lumière    
    float3 tV = normalize(input.tV);        //Caméra tangent
    float3 Hn = normalize(wV + wL);  //Vecteur caméra + direction lumière
    float2 texCoordinates = input.texCoordinates;   //Coordonnées de texture
    
    //Parallax mapping : modification des coordonnées de texture selon la heighttexture    
    float heightValue = tex2D(heightTextureSampler, texCoordinates).x;
    float parallaxHeight = heightValue * parallaxValue + sfHeightBias;
    texCoordinates = texCoordinates + tV.xy * parallaxHeight / tV.z; 
 
    //Couleur du pixel selon la texture (modifiée selon le parallax)
    float4 pixelColor = tex2D(coloredTextureSampler, texCoordinates);
    
    //Calcul de l'atténuation en fonction de la distance à la lumière    
    float lightDistance = norme(wLd);
    float lightPower = (lightDistance <= LightFallOffLimit1[numLight])? 
                            1 : 
                            max((LightFallOffLimit2[numLight] - lightDistance) / (LightFallOffLimit2[numLight] - LightFallOffLimit1[numLight]), 0);     

    
    //Bump : Modification de la tangente selon la normalMap
    float4 normalColor = tex2D(normalTextureSampler, texCoordinates) - float4(0.5, 0.5, 0.5, 0);
    
    wN = normalize( wN + 
                    3 * normalColor.r * wT * lightPower + 
                    3 * normalColor.g  * wB * lightPower);

    //Calcul du vecteur lumière
    float4 lv = lit(    dot(wL, wN), 
                        dot(Hn, wN), 
                        SpecExpon[numLight]);
                        
    //Calcul de chaque composante
    float4 ambient = AmbientColor;
    if( numLight != 0)
		    ambient = float4(0, 0, 0, 0);
		
    float4 diffuse = DiffuseColor[numLight] * lv.yyyy;
    //diffuse = diffuse + DiffuseColor[numLight];
    //diffuse /= 2;
    float4 specular = SpecularColor[numLight] * lv.zzzz;     
    
    //Calcul de l'illumination finale
    output = pixelColor * (ambient + diffuse * lightPower + specular * lightPower);
    
    //Sortie
    return output;
}

//Technique en plusieurs passes : un pour chaque lumière
technique technique0 {
    pass p0 {
        VertexShader = compile vs_3_0 mainVS();
        PixelShader = compile ps_3_0 mainPS(0);
    }
/*
    pass p1 {
        SRCBLEND = ONE;
        DESTBLEND = ONE;
        ALPHABLENDENABLE = true;
        VertexShader = compile vs_3_0 mainVS();
        PixelShader = compile ps_3_0 mainPS(1);
    }

    pass p2 {
        VertexShader = compile vs_3_0 mainVS();
        PixelShader = compile ps_3_0 mainPS(2);
    }
    
    pass p3 {
        VertexShader = compile vs_3_0 mainVS();
        PixelShader = compile ps_3_0 mainPS(3);
    }
    
	
    pass p4 {
        VertexShader = compile vs_3_0 mainVS();
        PixelShader = compile ps_3_0 mainPS(4);
    }
 */
}


